package com.kk.xhr.model.service.impl;

import com.kk.xhr.common.pojo.BinaryEnum;
import com.kk.xhr.model.dao.PermissionDynamicSqlSupport;
import com.kk.xhr.model.dao.PermissionMapper;
import com.kk.xhr.model.dao.RoleDynamicSqlSupport;
import com.kk.xhr.model.dao.RolePermissionDynamicSqlSupport;
import com.kk.xhr.model.dao.RolePermissionMapper;
import com.kk.xhr.model.dao.UserRoleDynamicSqlSupport;
import com.kk.xhr.model.dao.custom.PermissionCustomMapper;
import com.kk.xhr.model.dto.PermissionTreeDTO;
import com.kk.xhr.model.entity.Permission;
import com.kk.xhr.model.entity.RolePermission;
import com.kk.xhr.model.service.IPermissionService;
import lombok.RequiredArgsConstructor;
import org.mybatis.dynamic.sql.insert.render.MultiRowInsertStatementProvider;
import org.mybatis.dynamic.sql.render.RenderingStrategies;
import org.mybatis.dynamic.sql.select.render.SelectStatementProvider;
import org.springframework.stereotype.Repository;

import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import static com.kk.xhr.model.dao.RolePermissionDynamicSqlSupport.rolePermission;
import static org.mybatis.dynamic.sql.SqlBuilder.equalTo;
import static org.mybatis.dynamic.sql.SqlBuilder.insertMultiple;
import static org.mybatis.dynamic.sql.SqlBuilder.isEqualTo;
import static org.mybatis.dynamic.sql.select.SelectDSL.select;

/**
 * 权限接口实现
 *
 * @author kkmystery
 * @version 1.0 2021/3/9
 * @since 1.0.0
 */
@Repository
@RequiredArgsConstructor
public class PermissionServiceImpl implements IPermissionService {
    private final PermissionCustomMapper permissionCustomMapper;
    private final PermissionMapper permissionMapper;
    private final RolePermissionMapper rolePermissionMapper;

    /**
     * {@inheritDoc}
     */
    @Override
    public Set<String> queryPermissionsByUserId(Long userId) {
        SelectStatementProvider selectStatementProvider = select(PermissionDynamicSqlSupport.name)
            .from(PermissionDynamicSqlSupport.permission, "p")
            .join(RolePermissionDynamicSqlSupport.rolePermission, "rp")
            .on(RolePermissionDynamicSqlSupport.permissionId, equalTo(PermissionDynamicSqlSupport.id))
            .join(UserRoleDynamicSqlSupport.userRole, "ur")
            .on(UserRoleDynamicSqlSupport.roleId, equalTo(RolePermissionDynamicSqlSupport.roleId))
            .join(RoleDynamicSqlSupport.role, "r")
            .on(RoleDynamicSqlSupport.id, equalTo(UserRoleDynamicSqlSupport.roleId))
            .where(UserRoleDynamicSqlSupport.userId, isEqualTo(userId))
            .and(PermissionDynamicSqlSupport.status, isEqualTo((byte) 1))
            .and(RoleDynamicSqlSupport.status, isEqualTo((byte) 1))
            .build()
            .render(RenderingStrategies.MYBATIS3);
        return permissionMapper.selectMany(selectStatementProvider)
            .stream()
            .map(Permission::getName)
            .collect(Collectors.toSet());
    }

    @Override
    public PermissionTreeDTO query(Long id) {
        return permissionCustomMapper.query(id);
    }

    /**
     * 根据角色id获取权限树
     *
     * @param roleId 角色id
     * @return 权限主键id列表
     */
    @Override
    public List<Long> queryByRoleId(Long roleId) {
        SelectStatementProvider provider = select(RolePermissionDynamicSqlSupport.permissionId)
            .from(RolePermissionDynamicSqlSupport.rolePermission)
            .where(RolePermissionDynamicSqlSupport.roleId, isEqualTo(roleId))
            .build().render(RenderingStrategies.MYBATIS3);
        return rolePermissionMapper.selectMany(provider)
            .stream()
            .map(RolePermission::getPermissionId)
            .collect(Collectors.toList());
    }

    @Override
    public Long add(Permission permission) {
        permissionMapper.insertSelective(permission);
        return permission.getId();
    }

    @Override
    public boolean modify(Permission permission) {
        if (null == permission.getId()) {
            return false;
        }
        return 1 == permissionMapper.updateByPrimaryKeySelective(permission);
    }

    @Override
    public boolean modifyStatus(Long id, BinaryEnum status) {
        if (null == status) {
            return false;
        }
        return 1 == permissionMapper.updateByPrimaryKeySelective(new Permission().withId(id).withStatus(status.getValue()));
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void deletePermissionByRoleId(Long roleId) {
        rolePermissionMapper.delete(dsl -> dsl
            .where(RolePermissionDynamicSqlSupport.roleId, isEqualTo(roleId)));
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean batchInsert(Long roleId, List<Long> ids) {
        if (ids.isEmpty()) {
            return false;
        }
        List<RolePermission> list = ids
            .stream()
            .map(id -> new RolePermission().withPermissionId(id).withRoleId(roleId))
            .collect(Collectors.toList());
        MultiRowInsertStatementProvider<RolePermission> multiRowInsert = insertMultiple(list)
            .into(rolePermission)
            .map(RolePermissionDynamicSqlSupport.roleId).toProperty("roleId")
            .map(RolePermissionDynamicSqlSupport.permissionId).toProperty("permissionId")
            .build()
            .render(RenderingStrategies.MYBATIS3);
        return ids.size() == rolePermissionMapper.insertMultiple(multiRowInsert);
    }
}
